package net.myspring.common.mybatis.provider;

import com.google.common.collect.Maps;
import net.myspring.common.mybatis.provider.mapper.BaseMapper;
import net.myspring.common.utils.ReflectionUtils;
import net.myspring.common.utils.ThreadLocalContext;
import org.apache.ibatis.binding.MapperProxy;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.*;
import java.util.Map;

/**
 * Created by liuj on 2016/11/14.
 */

@Aspect
@Component
@Order(1)
public class ProviderMapperAspect {

    private static Map<String,ProviderContext> providerContextMap = Maps.newHashMap();

    private final static Logger logger = LoggerFactory.getLogger(ProviderMapperAspect.class);

    @Pointcut("execution(* net.myspring..*.mapper.*.*(..))")
    public void mapperExecution() {
    }

    @Before("mapperExecution()")
    public void setDynamicDataSource(JoinPoint point) {
        Class entityClass = null;
        Object target = point.getTarget();
        if(BaseMapper.class.isAssignableFrom(target.getClass())) {
            MapperProxy mapperProxy = (MapperProxy) Proxy.getInvocationHandler(target);
            Class mapperInterface = (Class) ReflectionUtils.getFieldValue(mapperProxy,"mapperInterface");
            ParameterizedType parameterizedType = (ParameterizedType) mapperInterface.getGenericInterfaces()[0];
            Type[] types = parameterizedType.getActualTypeArguments();
            try {
                entityClass = Class.forName(types[0].getTypeName());
                if(!providerContextMap.containsKey(entityClass.getName())) {
                    ProviderContext providerContext = new ProviderContext();
                    providerContext.setEntityClass(entityClass);
                    providerContext.setIdClass(Class.forName(types[1].getTypeName()));
                    providerContextMap.put(entityClass.getName(),providerContext);
                }
            } catch (ClassNotFoundException e) {
                logger.error(e.getMessage());
            }
        }
        ThreadLocalContext.get().setProviderContext(providerContextMap.get(entityClass==null?null:entityClass.getName()));
    }


}
